/**
 * @file    growatt_rs485.c
 * @brief   逆变器协议-古瑞瓦特-RS485协议
 * @author  Liuwei
 * @version 1.0.1
 * @date    2023-05-18
 * 
 * @copyright Copyright (c) 2023 JBD-Energy Storage Technology Co. LTD
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version   <th>Author   <th>Description
 * <tr><td>2023-04-30 <td>1.0.1     <td>Liuwei   <td>首次创建
 * </table>
 */

/* includes ------------------------------------------------------------------*/
#include "growatt_rs485.h"
#include "modbus_app.h"
#include "if_di.h"
#include "cfg_prj.h"
#include "dev_rtc.h"
#include "pc_jbd.h"
#include "var_mng.h"
#include "param_mng.h"
#include "sample.h"
#include "parallel.h"
#include "if_rtc.h"
/* macro/define --------------------------------------------------------------*/
typedef union 
{
    uint32_t time_data;
    struct 
    {
        uint32_t year : 6;
        uint32_t month : 4;
        uint32_t day : 5;
        uint32_t hour : 5;
        uint32_t min : 6;
        uint32_t sec : 6;
    }name;
}time_date_type;

typedef union 
{
    uint16_t half_data;
    struct growatt_rs485
    {
        uint16_t status : 2;
        uint16_t err_bit : 1;
        uint16_t cell_blc : 1;
        uint16_t sleep_status : 1;
        uint16_t dsg_output : 1;
        uint16_t chg_output : 1;
        uint16_t batt_connt : 1;
        uint16_t box_mode : 2;
        uint16_t SP_status : 2;
        uint16_t force_chg : 1;
    }name;
}status_type;

typedef union
{
    uint16_t half_data;
    struct 
    {
        uint16_t ocd : 1;
        uint16_t scd: 1;
        uint16_t ov : 1;
        uint16_t uv : 1;
        uint16_t otd : 1;
        uint16_t otc : 1;
        uint16_t utd : 1;
        uint16_t utc : 1;
        uint16_t soft_fail : 1;
        uint16_t per_fail : 1;
        uint16_t delta_fail : 1;
        uint16_t occ : 1;
		uint16_t otm : 1;
        uint16_t ote : 1;
        uint16_t ute : 1; 
    }name;
}error_type;

/* typedef -------------------------------------------------------------------*/
#define INTPUT_REG_SIZE      (0x81)
#define CMD_READ_IN_REG      (0x03)
#define CMD_WRITE_HOLD_REG   (0x10)

/* local functions -----------------------------------------------------------*/
static void growatt_read_input_reg(md_data_type md_data_msg , uint8_t *tx_buf ,uint16_t *tx_len);
static void growatt_cmd_0x10_deal(md_data_type md_data_msg , uint8_t *tx_buf ,uint16_t *tx_len);
static void growatt_update_input_buf(void);
static uint16_t get_status(void);
static uint16_t get_error(void);
/* static variables ----------------------------------------------------------*/
static uint16_t input_reg_buf[INTPUT_REG_SIZE] = {0};

/* global variables ----------------------------------------------------------*/

/** ------------------------------------------------------------------------- *
  *                             Global function
 ** ------------------------------------------------------------------------- */
uint8_t growatt_rs485_analysis(uint8_t *rx_buf , uint16_t rx_len ,uint8_t *tx_buf , uint16_t *tx_len)
{
    md_data_type recv_md_data = {0};
    if(TRUE == modbus_rtu_analysis(rx_buf , rx_len , &recv_md_data))
    {
        if(1 == recv_md_data.addr)
        {
            if((recv_md_data.reg_addr + recv_md_data.data_len <= INTPUT_REG_SIZE)
              &&(CMD_READ_IN_REG == recv_md_data.cmd_code))
            {
                growatt_update_input_buf();
                growatt_read_input_reg(recv_md_data , tx_buf , tx_len);
				
				return TRUE;
            }
			else if(CMD_WRITE_HOLD_REG == recv_md_data.cmd_code)
			{
				growatt_cmd_0x10_deal(recv_md_data , tx_buf , tx_len);
				
				return TRUE;
			}
			else
			{
				return FALSE;
			}
        }
        return FALSE;
    }
    return FALSE;
}

/** ------------------------------------------------------------------------- *
  *                              Local function
 ** ------------------------------------------------------------------------- */
static void growatt_read_input_reg(md_data_type md_data_msg , uint8_t *tx_buf ,uint16_t *tx_len)
{
    uint16_t data_len = 0;
    uint16_t crc_code = 0;
    uint8_t i = 0;
    uint8_t *p_tx = tx_buf;

    *p_tx ++ = md_data_msg.addr;
    *p_tx ++ = md_data_msg.cmd_code;
    data_len = md_data_msg.data_len * 2; 
    *p_tx ++ = data_len; 
   	
    for(i = 0;i < md_data_msg.data_len; ++ i)
    {
		
        *p_tx ++ = input_reg_buf[i + md_data_msg.reg_addr] >> 8;
        *p_tx ++  = input_reg_buf[i + md_data_msg.reg_addr] & 0xff;
    }
	
    crc_code = modbus_calc_crc(tx_buf , data_len + 3);

    *p_tx ++ = crc_code;
    *p_tx ++ = crc_code >> 8;

    *tx_len = (data_len + 5);
} 

static void growatt_cmd_0x10_deal(md_data_type md_data_msg , uint8_t *tx_buf ,uint16_t *tx_len)
{
    uint16_t crc_code = 0;
    uint8_t *p_tx = tx_buf;

    *p_tx ++ = md_data_msg.addr;
    *p_tx ++ = md_data_msg.cmd_code; 
	*p_tx ++ = md_data_msg.reg_addr >> 8; 
	*p_tx ++ = md_data_msg.reg_addr; 
    *p_tx ++ = md_data_msg.data_len >> 8; 
    *p_tx ++ = md_data_msg.data_len; 
	
    crc_code = modbus_calc_crc(tx_buf , 6);

    *p_tx ++ = crc_code;
    *p_tx ++ = crc_code >> 8;

    *tx_len = 8;
} 

static void growatt_update_input_buf(void)
{
    rtc_data_type rtc_time = {0};
    time_date_type now_time = {0};
	int16_t sys_curr = 0;
	uint16_t temp = 0;
	uint8_t i = 0;
	uint16_t soh = 0;
	uint32_t cap_val = 0;
    //input_reg_buf[0] = (SOFT_VER_MAIN << 8) + SOFT_VER_RELEASE;
    input_reg_buf[1] = (SOFT_VER_MAIN << 8) + SOFT_VER_RELEASE;
    input_reg_buf[2] = 0;
    input_reg_buf[3] = 0;
    input_reg_buf[4] = 0;

	If_rtc_read_time(&rtc_time);
 
    now_time.name.year = rtc_time.year - 2000;
    now_time.name.month = rtc_time.month;
    now_time.name.day = rtc_time.day;
    now_time.name.hour = rtc_time.hour;
    now_time.name.min = rtc_time.min;
    now_time.name.sec = rtc_time.sec;
    
    input_reg_buf[5] = (now_time.time_data >> 24)& 0xff;
    input_reg_buf[6] = (now_time.time_data >> 16)& 0xff;
    input_reg_buf[7] = (now_time.time_data >> 8) & 0xff;
    input_reg_buf[8] = (now_time.time_data & 0xff);

    input_reg_buf[9] = 0;
    input_reg_buf[0x0A] = 0;
    input_reg_buf[0x0B] = 0;
    input_reg_buf[0x0C] = 0;

    input_reg_buf[0x0D] = 0;
    input_reg_buf[0x0E] = 0;
    input_reg_buf[0x0F] = 5;
	
	sys_curr = master_data_reg.total_bus_curr;
    input_reg_buf[0x10] = sys_curr;
	
    input_reg_buf[0x11] = now_time.time_data >> 16;
    input_reg_buf[0x12] = now_time.time_data;   
    input_reg_buf[0x13] = get_status();
    input_reg_buf[0x14] = get_error();
	
    input_reg_buf[0x15] = master_data_reg.avg_soc;
    input_reg_buf[0x16] = master_data_reg.avg_batt_volt;
    input_reg_buf[0x17] = master_data_reg.total_bus_curr;
    input_reg_buf[0x18] = master_data_reg.avg_max_temp * 0.1-273.15;
	
    input_reg_buf[0x19] = var_get_data(VAR_ID_TP_SOP_CC)*10;	
	
	cap_val = master_data_reg.total_real_cap;
	if(cap_val >= MAX_DISP_CAP)
		cap_val = MAX_DISP_CAP;
    input_reg_buf[0x1A] = cap_val;
	
	cap_val = master_data_reg.total_full_cap;
	if(cap_val >= MAX_DISP_CAP)
		cap_val = MAX_DISP_CAP;
	input_reg_buf[0x1B] = cap_val;
	
    input_reg_buf[0x1C] = (uint16_t)(SOFT_VER_RELEASE << 8) + var_get_data(VAR_ID_HARD_VER);
	
	temp = ((master_data_reg.avg_max_volt + master_data_reg.avg_min_volt)*0.5);
	input_reg_buf[0x1D] = temp ;
    input_reg_buf[0x1E] = master_data_reg.avg_cycle;
    input_reg_buf[0x1F] = 0;
	soh = var_get_data(VAR_ID_TP_SOH);
	if(soh > 100)
		soh = 100;
    input_reg_buf[0x20] = soh;
	
    input_reg_buf[0x21] = var_get_data(VAR_ID_TP_SOP_CV)*10;
    input_reg_buf[0x22] = 0;
    input_reg_buf[0x23] = var_get_data(VAR_ID_TP_SOP_DC)*10;
    input_reg_buf[0x24] = 0;
	
    input_reg_buf[0x25] = master_data_reg.avg_max_volt;
    input_reg_buf[0x26] = master_data_reg.avg_min_volt;
    input_reg_buf[0x27] = 1;
    input_reg_buf[0x28] = 2;
    input_reg_buf[0x29] = param_get_data(PAR_ID_CB_CELL_NUM);
	
	input_reg_buf[0x70] = 0x01;
	for( i = 0;i <16; ++ i)
	{
		input_reg_buf[0x71 + i] = master_data_reg.avg_cell_buf[i]; 
	}
}

static uint16_t get_status(void)
{
    status_type now_status = {0};

    if(master_data_reg.total_bus_curr > 0)
        now_status.name.status = 2;
    else if(master_data_reg.total_bus_curr < 0)
        now_status.name.status = 3;
    else
        now_status.name.status = 1;

    now_status.name.err_bit = 0;
    now_status.name.cell_blc = 0;
    now_status.name.sleep_status = 0;
    now_status.name.chg_output = parallel_get_pcs_ctrl(PARALLEL_PCS_CHG_EN);
    now_status.name.dsg_output = parallel_get_pcs_ctrl(PARALLEL_PCS_DSG_EN);
    now_status.name.batt_connt = 0;
	if(master_data_reg.parallel_num > 1)
		now_status.name.box_mode = 0x01;
	else
		now_status.name.box_mode = 0x00;

    if(parallel_get_pcs_ctrl(PARALLEL_PCS_FROCE_CHG2))
        now_status.name.force_chg = 1;
    
    return now_status.half_data;
}

static uint16_t get_error(void)
{
    error_type error_code = {0};

    if(master_data_reg.total_prp_msg.bit.ocd || master_data_reg.total_prp_msg.bit.ocd2)
        error_code.name.ocd = 1;
    if(master_data_reg.total_prp_msg.bit.sc)
        error_code.name.scd = 1;   
    //if(diag_get_prp(PRP_ID_COV))
    //    error_code.name.cov = 1;   
    //if(diag_get_prp(PRP_ID_CUV))
    //    error_code.name.cuv = 1;
    if(master_data_reg.total_prp_msg.bit.otd)
        error_code.name.otd = 1;    
    if(master_data_reg.total_prp_msg.bit.otc)
        error_code.name.otc = 1;  
    if(master_data_reg.total_prp_msg.bit.utd)
        error_code.name.utd = 1;   
    if(master_data_reg.total_prp_msg.bit.utc)
        error_code.name.utc = 1; 
    if(master_data_reg.total_prp_msg.bit.occ)
        error_code.name.occ = 1;  
    if(master_data_reg.total_prp_msg.bit.otm)
        error_code.name.otm = 1;    
    if(master_data_reg.total_prp_msg.bit.ote)
        error_code.name.ote = 1; 
    if(master_data_reg.total_prp_msg.bit.ute)
        error_code.name.ute = 1;       

    return error_code.half_data;
}

/********** Copyright (c) 2023 JBD-Energy Storage Technology Co. LTD *********/
